/*
 * ServletContextStringTemplateGroup.java
 *
 * Copyright 2010 Jack Leow
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package my.edu.clhs.stringtemplate.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.ServletContext;

import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link StringTemplateGroup} implementation that loads {@link StringTemplate}s
 * from a Java EE web application Servlet context.
 *
 * Note that this class depends on undocumented {@link StringTemplateGroup}
 * implementation details that may change in the future.
 * 
 * @author Jack Leow
 * @version 1.0
 * @since 1.0 (Feb 20, 2010, 10:24:26 PM)
 */
public class ServletContextStringTemplateGroup extends StringTemplateGroup {
    public static final String DEFAULT_TEMPLATE_ROOT_PATH = "";
    private static final String GROUP_NAME =
        "my_edu_clhs_stringtemplate_servletContextGroup";
    
    private static final Logger log =
        LoggerFactory.getLogger(ServletContextStringTemplateGroup.class);
    
    private final ServletContext servletContext;
    
    /**
     * Creates a new <tt>ServletContextStringTemplateGroup</tt> with the
     * specified template root path and {@link ServletContext} for template
     * resolution.
     *
     * @param templateRootPath the template root path;
     *  defaults to {@link #DEFAULT_TEMPLATE_ROOT_PATH} if <tt>null</tt>
     * @param servletContext the ServletContext for template resolution
     */
    public ServletContextStringTemplateGroup(
            String templateRootPath, ServletContext servletContext) {
        super(GROUP_NAME);
        log.debug("entering this(String,ServletContext)");
        if (servletContext == null) {
            throw new NullPointerException("servletContext cannot be null");
        }
        this.servletContext = servletContext;
        setRootDir(templateRootPath != null ?
            templateRootPath : DEFAULT_TEMPLATE_ROOT_PATH);
        setErrorListener(new Slf4JErrorListener(log));
        log.debug("exiting this(String,ServletContext)");
    }
    
    /**
     * Loads the {@link StringTemplate} with the given name and file name within
     * the template root path, relative to the Servlet context root.
     * 
     * Note that this is an undocumented {@link StringTemplateGroup}
     * implementation detail that may change in the future releases.
     * 
     * Also note that <tt>fileName</tt> is a path to the file relative to the
     * servlet context root <i>not the <tt>rootDir</tt> as you might expect</i>.
     * This is to maintain compatibility with the overridden method.
     *
     * @param name the template name
     * @param fileName the template file name
     * @return the loaded template;
     *  or <tt>null</tt> if there is no such template
     */
    // @Override
    protected StringTemplate loadTemplate(String name, String fileName) {
        log.debug("entering loadTemplate(String,String)");
        InputStream is =
            servletContext.getResourceAsStream(fileName);
        BufferedReader br = null;
        StringTemplate template = null;
        
        if (is != null) {
            try {
                InputStreamReader isr = getInputStreamReader(is);
                br = new BufferedReader(isr);
                template = loadTemplate(name, br);
            } catch (IOException e) {
                error("Error loading template from file: " + fileName);
                throw new RuntimeException(e);
            } finally {
                if ( br != null ) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        error("Cannot close template file: " + fileName);
                    }
                }
            }
        }

        log.debug("exiting loadTemplate(String,String)");
        return template;
    }
}